Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
Registered S3 method overwritten by 'cli':
  method     from    
  print.boxx spatstat
── Attaching packages ─────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ tibble  3.0.6     ✓ dplyr   1.0.4
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
✓ purrr   0.3.4     
── Conflicts ────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::between()   masks data.table::between()
x tidyr::expand()    masks Matrix::expand()
x dplyr::filter()    masks plotly::filter(), stats::filter()
x dplyr::first()     masks data.table::first()
x dplyr::lag()       masks stats::lag()
x dplyr::last()      masks data.table::last()
x tidyr::pack()      masks Matrix::pack()
x purrr::transpose() masks data.table::transpose()
x tidyr::unpack()    masks Matrix::unpack()

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

The following object is masked from ‘package:plotly’:

    select

---------------------
Welcome to dendextend version 1.14.0
Type citation('dendextend') for how to cite the package.

Type browseVignettes(package = 'dendextend') for the package vignette.
The github page is: https://github.com/talgalili/dendextend/

Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
Or contact: <tal.galili@gmail.com>

    To suppress this message use:  suppressPackageStartupMessages(library(dendextend))
---------------------


Attaching package: ‘dendextend’

The following object is masked from ‘package:data.table’:

    set

The following object is masked from ‘package:stats’:

    cutree

To demostrate how to do the gene clustering usign COTAN we begin importing the COTAN object that stores all elaborated data and, in this case, regarding a mouse embrionic cortex dataset (developmental stage E17.5).

[1] "calculating gene coexpression space: output tanh of reduced coex matrix"
     L11      L12    L2/31    L2/32      L41      L42    L5/61    L5/62    Prog1    Prog2 
  "Reln"   "Lhx5"  "Satb2"   "Cux1"   "Rorb"   "Sox5" "Bcl11b"  "Fezf2"    "Vim"   "Hes1" 
[1] "Get p-values on a set of genes on columns genome wide on rows"
[1] "Using function S"
[1] "function to generate S "
[1] "function to generate S "

Hierarchical clustering

or just with primary markers

Now we can plot the PCA

# some more genes as landmarks
controls =list("genes related to L5/6"=c("Foxp2","Tbr1"), "genes related to L2/3"=c("Mef2c"), "genes related to Prog"=c("Nes","Sox2") , "genes related to L1"=c() , "genes related to L4"=c()) 

# dataframe to be able to label only primary markers and control genes
textdf <- pca_1[rownames(pca_1) %in% c(unlist(layers),unlist(controls)) , ]

 for (m in c(1:length(controls))) {
  for (g in controls[[m]]) {
    if(g %in% rownames(textdf)){
      textdf[g,"highlight"] = names(controls[m])
    } 
  }
}

# deciding the colors
mycolours <- c("genes related to L5/6" = "#3C5488FF","genes related to L2/3"="#F39B7FFF","genes related to Prog"="#4DBBD5FF","genes related to L1"="#E64B35FF","genes related to L4" = "#91D1C2FF", "not marked"="#B09C85FF")

# to assing correcly the cluster number and the color
mycolours2 = c("Reln","Satb2","Rorb","Bcl11b","Vim")
names(mycolours2) = unique(cut[unlist(layers)])

mycolours2[mycolours2 == "Reln"] = "#E64B35FF"
mycolours2[mycolours2 == "Satb2"] = "#F39B7FFF"
mycolours2[mycolours2 == "Rorb"] = "#91D1C2FF"
mycolours2[mycolours2 == "Bcl11b"] = "#3C5488FF"
mycolours2[mycolours2 == "Vim"] = "#4DBBD5FF"
color_to_add = unique(pca_1$hclust)[!unique(pca_1$hclust) %in% as.numeric(names(mycolours2))]
names(color_to_add) = unique(pca_1$hclust)[!unique(pca_1$hclust) %in% as.numeric(names(mycolours2))]
color_to_add[color_to_add %in% 
                 unique(pca_1$hclust)[!unique(pca_1$hclust) %in% as.numeric(names(mycolours2))]] = "#B09C85FF"
mycolours2 = c(mycolours2,color_to_add)

pca1 = ggplot(subset(pca_1,!hclust %in% unique(cut[unlist(layers)])  ), aes(x=PC1, y=PC2)) +  geom_point(alpha = 0.3,color = "#B09C85FF",size=1)

#pca2 = pca1 + geom_point(data = subset(pca_1, highlight != "not marked" ), aes(x=PC1, y=PC2, colour=hclust),size=2.5,alpha = 0.9) 
pca2 = pca1 + geom_point(data = subset(pca_1, hclust %in% unique(cut[unlist(layers)]) ), aes(x=PC1, y=PC2, colour=as.character(hclust)),size=1,alpha = 0.5) + 
 scale_color_manual( "Status", values = mycolours2)  +
  scale_fill_manual( "Status", values = mycolours2)  +
  xlab("") + ylab("") +
  geom_label_repel(data =textdf , aes(x = PC1, y = PC2, label = rownames(textdf),fill=as.character(hclust)),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction = "both",
                   na.rm=TRUE,
                   seed = 1234) +
  geom_label_repel(data =textdf , aes(x = PC1, y = PC2, label = rownames(textdf)),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234) +
  ggtitle("PCA") +
  theme_light(base_size=10) +
    theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.position = "none")  # titl)

pca2 #+ geom_encircle(data = pca_1, aes(group=hclust)) 

t-SNE code and plot

# run the t-SNE
cl.genes.tsne = Rtsne(g.space ,initial_dims = 100, dims = 2, perplexity=30,eta = 200, verbose=F, max_iter = 3000,theta=0.4,num_threads = 10,pca_center = T, pca_scale = FALSE, normalize = T )

d_tsne_1 = as.data.frame(cl.genes.tsne$Y)
rownames(d_tsne_1) = rownames(g.space)

d_tsne_1 = d_tsne_1[order.dendrogram(dend),]

# save the cluster numebr inside a dataframe with the t-SNE information
d_tsne_1$hclust = cut

d_tsne_1$names = rownames(d_tsne_1)

# as before to label only some genes
textdf <- d_tsne_1[rownames(d_tsne_1) %in% c(unlist(layers),unlist(controls)),]

for (m in c(1:length(controls))) {
  for (g in controls[[m]]) {
    if(g %in% rownames(textdf)){
      textdf[g,"highlight"] = names(controls[m])
    } 
  }
}


 p1 = ggplot(subset(d_tsne_1,!hclust %in% unique(cut[unlist(layers)])), aes(x=V1, y=V2)) +  geom_point(alpha = 0.3, color = "#B09C85FF", size=1)

p2 = p1 + geom_point(data = subset(d_tsne_1, hclust %in% unique(cut[unlist(layers)]) ), aes(x=V1, y=V2, colour=as.character(hclust)),size=1,alpha = 0.5) +
    scale_color_manual("Status", values = mycolours2)  +
  scale_fill_manual("Status", values = mycolours2)  +
  xlab("") + ylab("")+
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = names,fill=as.character(hclust)),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction = "both",
                   na.rm=TRUE,
                   seed = 1234) +
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = names),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234) +
  ggtitle("t-SNE") +
  theme_light(base_size=10) +
  theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.position = "none")  # titl)
p2

Code to create an iteractive plot. This can be modified to be used with all the plots.

Multidimensional scaling (MDS) and plot

initial  value 12.149889 
final  value 10.248596 
converged
fit.genes = as.data.frame(fit$points)

fit.genes = fit.genes[order.dendrogram(dend),]

fit.genes$hclust = cut


fit.genes$names = rownames(fit.genes)

mycolours3 <- c("cluster L5/6 markers" = "#3C5488FF","cluster L2/3 markers"="#F39B7FFF","cluster Prog markers"="#4DBBD5FF","cluster L1 markers"="#E64B35FF","cluster L4 markers" = "#91D1C2FF", "not identified cluster"="#B09C85FF")

#fit.genes$hclust = factor(cutree(hc.norm, 7))
used = vector()
for (k in c(1:length(layers))) {
  #print(k)
  tt =as.numeric(cut[layers[[k]]][1])
  fit.genes[fit.genes$hclust == tt,"cluster"] = paste("cluster",names(layers[k]),"markers", sep = " " )
  used = c(used,cut[layers[[k]]][1])
}

fit.genes[fit.genes$hclust %in% (unique(fit.genes$hclust)[!unique(fit.genes$hclust) %in% used]),]$cluster = "not identified cluster"

textdf <- fit.genes[rownames(fit.genes) %in% c(unlist(layers),unlist(controls)),]

   f1 = ggplot(subset(fit.genes,!hclust %in% unique(cut[unlist(layers)]) ), aes(x=V1, y=V2)) +  geom_point(alpha = 0.3, color = "#B09C85FF", size=1)

f2 = f1 + geom_point(data = subset(fit.genes, hclust %in% unique(cut[unlist(layers)]) ), 
                     aes(x=V1, y=V2, colour=cluster), size=1,alpha = 0.5) +
  scale_color_manual("Status", values = mycolours3)  +
  scale_fill_manual("Status", values = mycolours3)  + 
  xlab("") + ylab("")+
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = rownames(textdf),fill=cluster),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction ="both",
                   na.rm=TRUE,
                   seed = 1234, show.legend = FALSE) +
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = rownames(textdf)),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234, show.legend = FALSE) +
  ggtitle("MDS") +
  theme_light(base_size=10) +
  theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.title = element_blank(),
        legend.text = element_text(color = "#3C5488FF",face ="italic" ),
        legend.position = "bottom")  # titl)


f2 #+ geom_encircle(data = fit.genes, aes(group=`5_clusters`)) 

R version 4.0.4 (2021-02-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.5 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] dendextend_1.14.0 MASS_7.3-53.1     htmlwidgets_1.5.3 forcats_0.5.1     stringr_1.4.0     dplyr_1.0.4      
 [7] purrr_0.3.4       readr_1.4.0       tidyr_1.1.2       tibble_3.0.6      tidyverse_1.3.0   plotly_4.9.3     
[13] Rtsne_0.15        factoextra_1.0.7  ggrepel_0.9.1     ggplot2_3.3.3     Matrix_1.3-2      data.table_1.13.6
[19] COTAN_0.1.0      

loaded via a namespace (and not attached):
  [1] readxl_1.3.1         backports_1.2.1      circlize_0.4.12      plyr_1.8.6           igraph_1.2.6        
  [6] lazyeval_0.2.2       splines_4.0.4        crosstalk_1.1.1      listenv_0.8.0        scattermore_0.7     
 [11] digest_0.6.27        htmltools_0.5.1.1    viridis_0.5.1        magrittr_2.0.1       tensor_1.5          
 [16] cluster_2.1.1        ROCR_1.0-11          openxlsx_4.2.3       ComplexHeatmap_2.6.2 globals_0.14.0      
 [21] modelr_0.1.8         matrixStats_0.58.0   colorspace_2.0-0     rvest_0.3.6          rappdirs_0.3.3      
 [26] haven_2.3.1          xfun_0.20            crayon_1.4.0         jsonlite_1.7.2       spatstat_1.64-1     
 [31] spatstat.data_2.0-0  survival_3.2-7       zoo_1.8-8            glue_1.4.2           polyclip_1.10-0     
 [36] gtable_0.3.0         leiden_0.3.7         GetoptLong_1.0.5     car_3.0-10           future.apply_1.7.0  
 [41] shape_1.4.5          BiocGenerics_0.36.0  abind_1.4-5          scales_1.1.1         DBI_1.1.1           
 [46] rstatix_0.7.0        miniUI_0.1.1.1       Rcpp_1.0.6           viridisLite_0.3.0    xtable_1.8-4        
 [51] clue_0.3-58          reticulate_1.18      foreign_0.8-81       latex2exp_0.4.0      stats4_4.0.4        
 [56] httr_1.4.2           RColorBrewer_1.1-2   ellipsis_0.3.1       Seurat_4.0.0         ica_1.0-2           
 [61] pkgconfig_2.0.3      farver_2.0.3         sass_0.3.1           uwot_0.1.10          dbplyr_2.1.0        
 [66] deldir_0.2-10        tidyselect_1.1.0     labeling_0.4.2       rlang_0.4.10         reshape2_1.4.4      
 [71] later_1.1.0.1        cellranger_1.1.0     munsell_0.5.0        tools_4.0.4          cli_2.3.0           
 [76] generics_0.1.0       broom_0.7.5          ggridges_0.5.3       evaluate_0.14        fastmap_1.1.0       
 [81] yaml_2.2.1           goftest_1.2-2        fs_1.5.0             knitr_1.31           fitdistrplus_1.1-3  
 [86] zip_2.1.1            RANN_2.6.1           pbapply_1.4-3        future_1.21.0        nlme_3.1-152        
 [91] mime_0.9             xml2_1.3.2           rstudioapi_0.13      compiler_4.0.4       curl_4.3            
 [96] filelock_1.0.2       png_0.1-7            ggsignif_0.6.1       spatstat.utils_2.0-0 reprex_1.0.0        
[101] bslib_0.2.4          stringi_1.5.3        basilisk.utils_1.2.2 lattice_0.20-41      vctrs_0.3.6         
[106] pillar_1.4.7         lifecycle_0.2.0      lmtest_0.9-38        jquerylib_0.1.3      GlobalOptions_0.1.2 
[111] RcppAnnoy_0.0.18     cowplot_1.1.1        irlba_2.3.3          httpuv_1.5.5         patchwork_1.1.1     
[116] R6_2.5.0             promises_1.1.1       rio_0.5.16           KernSmooth_2.23-18   gridExtra_2.3       
[121] IRanges_2.24.1       parallelly_1.23.0    codetools_0.2-18     assertthat_0.2.1     rjson_0.2.20        
[126] withr_2.4.1          SeuratObject_4.0.0   sctransform_0.3.2    S4Vectors_0.28.1     mgcv_1.8-33         
[131] parallel_4.0.4       hms_1.0.0            grid_4.0.4           rpart_4.1-15         basilisk_1.2.1      
[136] rmarkdown_2.7        carData_3.0-4        Cairo_1.5-12.2       ggpubr_0.4.0         shiny_1.6.0         
[141] lubridate_1.7.9.2   
LS0tCnRpdGxlOiAiR2VuZV9jbHVzdGVyaW5nIgpvdXRwdXQ6CiAgICBodG1sX25vdGVib29rOgogICAgICBjc3M6IGh0bWwtbWQtMDEuY3NzCiAgICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICAgIHRoZW1lOiBzcGFjZWxhYgogICAgICB0b2M6IHllcwogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgY29sbGFwc2VkOiBubwotLS0KCmBgYHtyLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBjb2xsYXBzZSA9IFRSVUUsCiAgY29tbWVudCA9ICIjPiIsCiAgZmlnLndpZHRoID0gNywKICBmaWcuaGVpZ2h0ID0gNwopCmBgYAoKYGBge3Igc2V0dXB9CgpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkoQ09UQU4pCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShSdHNuZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZGVuZGV4dGVuZCkKYGBgCgpUbyBkZW1vc3RyYXRlIGhvdyB0byBkbyB0aGUgZ2VuZSBjbHVzdGVyaW5nIHVzaWduIENPVEFOIHdlIGJlZ2luIGltcG9ydGluZyB0aGUgQ09UQU4gb2JqZWN0IHRoYXQgc3RvcmVzIGFsbCBlbGFib3JhdGVkIGRhdGEgYW5kLCBpbiB0aGlzIGNhc2UsIHJlZ2FyZGluZyBhIG1vdXNlIGVtYnJpb25pYyBjb3J0ZXggZGF0YXNldCAoZGV2ZWxvcG1lbnRhbCBzdGFnZSBFMTcuNSkuCgpgYGB7cn0KaW5wdXRfZGlyID0gIkRhdGEvIgpsYXllcnMgPSBsaXN0KCJMMSI9YygiUmVsbiIsIkxoeDUiKSwgIkwyLzMiPWMoIlNhdGIyIiwiQ3V4MSIpLCAiTDQiPWMoIlJvcmIiLCJTb3g1IikgLCAiTDUvNiI9YygiQmNsMTFiIiwiRmV6ZjIiKSAsICJQcm9nIj1jKCJWaW0iLCJIZXMxIikpCiNvYmpFMTcgPSByZWFkUkRTKGZpbGUgPSBwYXN0ZShpbnB1dF9kaXIsIkUxNy41X2NvcnRleC5jb3Rhbi5SRFMiLCBzZXAgPSAiIikpCm9iakUxNyA9IHJlYWRSRFMoZmlsZSA9IHBhc3RlKGlucHV0X2RpciwiRTE3LjVfY29ydGV4LmNvdGFuLlJEUyIsIHNlcCA9ICIiKSkKYGBgCgpgYGB7cn0KZy5zcGFjZSA9IGdldC5nZW5lLmNvZXhwcmVzc2lvbi5zcGFjZShvYmpFMTcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uZ2VuZXMuZm9yLm1hcmtlciA9IDI4LCMyNSAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbWFyeS5tYXJrZXJzID0gdW5saXN0KGxheWVycykpCmBgYApgYGB7cn0KZy5zcGFjZSA9IGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KGcuc3BhY2UpKQoKY29leC5wY2EuZ2VuZXMgPC0gcHJjb21wKHQoZy5zcGFjZSksCiAgICAgICAgICAgICAgICAgY2VudGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICBzY2FsZS4gPSBGKSAKCmZ2aXpfZWlnKGNvZXgucGNhLmdlbmVzLCBhZGRsYWJlbHM9VFJVRSxuY3AgPSAxMCkKI2Z2aXpfZWlnKGNvZXgucGNhLmdlbmVzLCBjaG9pY2UgPSAiZWlnZW52YWx1ZSIsIGFkZGxhYmVscz1UUlVFKQpgYGAKSGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcKYGBge3J9CgojIGNsdXN0ZXJpbmcgdXNpZ24gV2FyZCBtZXRob2QKaGMubm9ybSA9IGhjbHVzdChkaXN0KGcuc3BhY2UpLCBtZXRob2QgPSAid2FyZC5EMiIpCgojIGFuZCBjdXQgdGhlIHRyZWUgaW50byA1IGNsdXN0ZXJzIChmb3IgZXhhbXBsZSkKY3V0ID0gY3V0cmVlKGhjLm5vcm0sIGsgPSA3LCBvcmRlcl9jbHVzdGVyc19hc19kYXRhID0gRikKCiMgSXQgY3JhdGVzIHRoZSB0cmVlCmRlbmQgPC0gYXMuZGVuZHJvZ3JhbShoYy5ub3JtKQoKIyBJIGNhbiB1c2UgYSBkYXRhZnJhbWUgZnJvbSB0aGUgcGNhIHRvIHN0b3JlIHNvbWUgZGF0YSByZWdhcmRpbmcgdGhlIGNsdXN0ZXJpbmcKcGNhXzEgPSBhcy5kYXRhLmZyYW1lKGNvZXgucGNhLmdlbmVzJHJvdGF0aW9uWywxOjVdKQpwY2FfMSA9IHBjYV8xW29yZGVyLmRlbmRyb2dyYW0oZGVuZCksXQoKCm15Y29sb3VycyA8LSBjKCJnZW5lcyByZWxhdGVkIHRvIEw1LzYiID0gIiMzQzU0ODhGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDIvMyI9IiNGMzlCN0ZGRiIsImdlbmVzIHJlbGF0ZWQgdG8gUHJvZyI9IiM0REJCRDVGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDEiPSIjRTY0QjM1RkYiLCJnZW5lcyByZWxhdGVkIHRvIEw0IiA9ICIjOTFEMUMyRkYiLCAibm90IG1hcmtlZCI9IiNCMDlDODVGRiIpCgojIHNhdmUgdGhlIGNsdXN0ZXIgbnVtYmVyIGludG8gdGhlIGRhdGFmcmFtZQpwY2FfMSRoY2x1c3QgPSBjdXQKCmRlbmQgPWJyYW5jaGVzX2NvbG9yKGRlbmQsaz03LGNvbD1jKCIjNERCQkQ1RkYiLCIjOTFEMUMyRkYiLCIjRjM5QjdGRkYiLCIjRTY0QjM1RkYiLCIjM0M1NDg4RkYiLCIjOTFEMUMyRkYiLCIjQjA5Qzg1RkYiICksZ3JvdXBMYWJlbHMgPSBUKQojZGVuZCA9Y29sb3JfbGFiZWxzKGRlbmQsaz01LGxhYmVscyA9IHJvd25hbWVzKHBjYV8xKSxjb2w9cGNhXzEkY29sb3JzKQoKCgojIHBsb3QgdGhlIGRlbmRyb2dyYW0gd2l0aCBhbGwgYW5tZXMgZm9yIHNlY29uZGFyeSBtYXJrZXJzCmRlbmQgJT4lCiAgc2V0KCJsYWJlbHMiLCBpZmVsc2UobGFiZWxzKGRlbmQpICVpbiUgcm93bmFtZXMocGNhXzEpW3Jvd25hbWVzKHBjYV8xKSAlaW4lIGNvbG5hbWVzKGFzLm1hdHJpeChnLnNwYWNlKSldLCBsYWJlbHMoZGVuZCksICIiKSkgJT4lCiAgIyAgc2V0KCJicmFuY2hlc19rX2NvbG9yIiwgdmFsdWUgPSBjKCJncmF5ODAiLCIjNERCQkQ1RkYiLCIjOTFEMUMyRkYiICwiZ3JheTgwIiwiI0YzOUI3RkZGIiwiI0U2NEIzNUZGIiwiIzNDNTQ4OEZGIiksIGsgPSA3KSAlPiUKIHBsb3QoaG9yaXo9RiwgYXhlcz1UKSMseWxpbSA9IGMoMCw4MCkpCgpgYGAKb3IganVzdCB3aXRoIHByaW1hcnkgbWFya2VycwoKYGBge3IgZmlnLndpZHRoPSAxMH0KCmRlbmQgJT4lCnNldCgibGFiZWxzIiwgaWZlbHNlKGxhYmVscyhkZW5kKSAlaW4lIHJvd25hbWVzKHBjYV8xKVtyb3duYW1lcyhwY2FfMSkgJWluJSB1bmxpc3QobGF5ZXJzKV0sIGxhYmVscyhkZW5kKSwgIiIpKSAlPiUKICBzZXQoImJyYW5jaGVzX2tfY29sb3IiLCB2YWx1ZSA9IGMoImdyYXk4MCIsIiM0REJCRDVGRiIsIiM5MUQxQzJGRiIgLCJncmF5ODAiLCIjRjM5QjdGRkYiLCIjRTY0QjM1RkYiLCIjM0M1NDg4RkYiKSwgayA9IDcpICU+JQpwbG90KGhvcml6PUYsIGF4ZXM9VCx5bGltID0gYygwLDEwMCkpCgpgYGAKCk5vdyB3ZSBjYW4gcGxvdCB0aGUgUENBCmBgYHtyfQojIHNvbWUgbW9yZSBnZW5lcyBhcyBsYW5kbWFya3MKY29udHJvbHMgPWxpc3QoImdlbmVzIHJlbGF0ZWQgdG8gTDUvNiI9YygiRm94cDIiLCJUYnIxIiksICJnZW5lcyByZWxhdGVkIHRvIEwyLzMiPWMoIk1lZjJjIiksICJnZW5lcyByZWxhdGVkIHRvIFByb2ciPWMoIk5lcyIsIlNveDIiKSAsICJnZW5lcyByZWxhdGVkIHRvIEwxIj1jKCkgLCAiZ2VuZXMgcmVsYXRlZCB0byBMNCI9YygpKSAKCiMgZGF0YWZyYW1lIHRvIGJlIGFibGUgdG8gbGFiZWwgb25seSBwcmltYXJ5IG1hcmtlcnMgYW5kIGNvbnRyb2wgZ2VuZXMKdGV4dGRmIDwtIHBjYV8xW3Jvd25hbWVzKHBjYV8xKSAlaW4lIGModW5saXN0KGxheWVycyksdW5saXN0KGNvbnRyb2xzKSkgLCBdCgogZm9yIChtIGluIGMoMTpsZW5ndGgoY29udHJvbHMpKSkgewogIGZvciAoZyBpbiBjb250cm9sc1tbbV1dKSB7CiAgICBpZihnICVpbiUgcm93bmFtZXModGV4dGRmKSl7CiAgICAgIHRleHRkZltnLCJoaWdobGlnaHQiXSA9IG5hbWVzKGNvbnRyb2xzW21dKQogICAgfSAKICB9Cn0KCiMgZGVjaWRpbmcgdGhlIGNvbG9ycwpteWNvbG91cnMgPC0gYygiZ2VuZXMgcmVsYXRlZCB0byBMNS82IiA9ICIjM0M1NDg4RkYiLCJnZW5lcyByZWxhdGVkIHRvIEwyLzMiPSIjRjM5QjdGRkYiLCJnZW5lcyByZWxhdGVkIHRvIFByb2ciPSIjNERCQkQ1RkYiLCJnZW5lcyByZWxhdGVkIHRvIEwxIj0iI0U2NEIzNUZGIiwiZ2VuZXMgcmVsYXRlZCB0byBMNCIgPSAiIzkxRDFDMkZGIiwgIm5vdCBtYXJrZWQiPSIjQjA5Qzg1RkYiKQoKIyB0byBhc3NpbmcgY29ycmVjbHkgdGhlIGNsdXN0ZXIgbnVtYmVyIGFuZCB0aGUgY29sb3IKbXljb2xvdXJzMiA9IGMoIlJlbG4iLCJTYXRiMiIsIlJvcmIiLCJCY2wxMWIiLCJWaW0iKQpuYW1lcyhteWNvbG91cnMyKSA9IHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKQoKbXljb2xvdXJzMltteWNvbG91cnMyID09ICJSZWxuIl0gPSAiI0U2NEIzNUZGIgpteWNvbG91cnMyW215Y29sb3VyczIgPT0gIlNhdGIyIl0gPSAiI0YzOUI3RkZGIgpteWNvbG91cnMyW215Y29sb3VyczIgPT0gIlJvcmIiXSA9ICIjOTFEMUMyRkYiCm15Y29sb3VyczJbbXljb2xvdXJzMiA9PSAiQmNsMTFiIl0gPSAiIzNDNTQ4OEZGIgpteWNvbG91cnMyW215Y29sb3VyczIgPT0gIlZpbSJdID0gIiM0REJCRDVGRiIKY29sb3JfdG9fYWRkID0gdW5pcXVlKHBjYV8xJGhjbHVzdClbIXVuaXF1ZShwY2FfMSRoY2x1c3QpICVpbiUgYXMubnVtZXJpYyhuYW1lcyhteWNvbG91cnMyKSldCm5hbWVzKGNvbG9yX3RvX2FkZCkgPSB1bmlxdWUocGNhXzEkaGNsdXN0KVshdW5pcXVlKHBjYV8xJGhjbHVzdCkgJWluJSBhcy5udW1lcmljKG5hbWVzKG15Y29sb3VyczIpKV0KY29sb3JfdG9fYWRkW2NvbG9yX3RvX2FkZCAlaW4lIAogICAgICAgICAgICAgICAgIHVuaXF1ZShwY2FfMSRoY2x1c3QpWyF1bmlxdWUocGNhXzEkaGNsdXN0KSAlaW4lIGFzLm51bWVyaWMobmFtZXMobXljb2xvdXJzMikpXV0gPSAiI0IwOUM4NUZGIgpteWNvbG91cnMyID0gYyhteWNvbG91cnMyLGNvbG9yX3RvX2FkZCkKCnBjYTEgPSBnZ3Bsb3Qoc3Vic2V0KHBjYV8xLCFoY2x1c3QgJWluJSB1bmlxdWUoY3V0W3VubGlzdChsYXllcnMpXSkgICksIGFlcyh4PVBDMSwgeT1QQzIpKSArICBnZW9tX3BvaW50KGFscGhhID0gMC4zLGNvbG9yID0gIiNCMDlDODVGRiIsc2l6ZT0xKQoKI3BjYTIgPSBwY2ExICsgZ2VvbV9wb2ludChkYXRhID0gc3Vic2V0KHBjYV8xLCBoaWdobGlnaHQgIT0gIm5vdCBtYXJrZWQiICksIGFlcyh4PVBDMSwgeT1QQzIsIGNvbG91cj1oY2x1c3QpLHNpemU9Mi41LGFscGhhID0gMC45KSAKcGNhMiA9IHBjYTEgKyBnZW9tX3BvaW50KGRhdGEgPSBzdWJzZXQocGNhXzEsIGhjbHVzdCAlaW4lIHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKSApLCBhZXMoeD1QQzEsIHk9UEMyLCBjb2xvdXI9YXMuY2hhcmFjdGVyKGhjbHVzdCkpLHNpemU9MSxhbHBoYSA9IDAuNSkgKyAKIHNjYWxlX2NvbG9yX21hbnVhbCggIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgc2NhbGVfZmlsbF9tYW51YWwoICJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMyKSAgKwogIHhsYWIoIiIpICsgeWxhYigiIikgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9dGV4dGRmICwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gcm93bmFtZXModGV4dGRmKSxmaWxsPWFzLmNoYXJhY3RlcihoY2x1c3QpKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IHJvd25hbWVzKHRleHRkZikpLAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLCAKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCkgKwogIGdndGl0bGUoIlBDQSIpICsKICB0aGVtZV9saWdodChiYXNlX3NpemU9MTApICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSxwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSJpdGFsaWMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9IiMzQzU0ODhGRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0PTAuMDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVoZWlnaHQ9MS4yLG1hcmdpbiA9IG1hcmdpbih0ID0gNSwgYiA9IC0xNSkpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICAjIHRpdGwpCgpwY2EyICMrIGdlb21fZW5jaXJjbGUoZGF0YSA9IHBjYV8xLCBhZXMoZ3JvdXA9aGNsdXN0KSkgCmBgYAoKdC1TTkUgY29kZSBhbmQgcGxvdAoKYGBge3J9CiMgcnVuIHRoZSB0LVNORQpjbC5nZW5lcy50c25lID0gUnRzbmUoZy5zcGFjZSAsaW5pdGlhbF9kaW1zID0gMTAwLCBkaW1zID0gMiwgcGVycGxleGl0eT0zMCxldGEgPSAyMDAsIHZlcmJvc2U9RiwgbWF4X2l0ZXIgPSAzMDAwLHRoZXRhPTAuNCxudW1fdGhyZWFkcyA9IDEwLHBjYV9jZW50ZXIgPSBULCBwY2Ffc2NhbGUgPSBGQUxTRSwgbm9ybWFsaXplID0gVCApCgpkX3RzbmVfMSA9IGFzLmRhdGEuZnJhbWUoY2wuZ2VuZXMudHNuZSRZKQpyb3duYW1lcyhkX3RzbmVfMSkgPSByb3duYW1lcyhnLnNwYWNlKQoKZF90c25lXzEgPSBkX3RzbmVfMVtvcmRlci5kZW5kcm9ncmFtKGRlbmQpLF0KCiMgc2F2ZSB0aGUgY2x1c3RlciBudW1lYnIgaW5zaWRlIGEgZGF0YWZyYW1lIHdpdGggdGhlIHQtU05FIGluZm9ybWF0aW9uCmRfdHNuZV8xJGhjbHVzdCA9IGN1dAoKZF90c25lXzEkbmFtZXMgPSByb3duYW1lcyhkX3RzbmVfMSkKCiMgYXMgYmVmb3JlIHRvIGxhYmVsIG9ubHkgc29tZSBnZW5lcwp0ZXh0ZGYgPC0gZF90c25lXzFbcm93bmFtZXMoZF90c25lXzEpICVpbiUgYyh1bmxpc3QobGF5ZXJzKSx1bmxpc3QoY29udHJvbHMpKSxdCgpmb3IgKG0gaW4gYygxOmxlbmd0aChjb250cm9scykpKSB7CiAgZm9yIChnIGluIGNvbnRyb2xzW1ttXV0pIHsKICAgIGlmKGcgJWluJSByb3duYW1lcyh0ZXh0ZGYpKXsKICAgICAgdGV4dGRmW2csImhpZ2hsaWdodCJdID0gbmFtZXMoY29udHJvbHNbbV0pCiAgICB9IAogIH0KfQoKCiBwMSA9IGdncGxvdChzdWJzZXQoZF90c25lXzEsIWhjbHVzdCAlaW4lIHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKSksIGFlcyh4PVYxLCB5PVYyKSkgKyAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAiI0IwOUM4NUZGIiwgc2l6ZT0xKQoKcDIgPSBwMSArIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChkX3RzbmVfMSwgaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pICksIGFlcyh4PVYxLCB5PVYyLCBjb2xvdXI9YXMuY2hhcmFjdGVyKGhjbHVzdCkpLHNpemU9MSxhbHBoYSA9IDAuNSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMyKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMyKSAgKwogIHhsYWIoIiIpICsgeWxhYigiIikrCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID10ZXh0ZGYgLCBhZXMoeCA9IFYxLCB5ID0gVjIsIGxhYmVsID0gbmFtZXMsZmlsbD1hcy5jaGFyYWN0ZXIoaGNsdXN0KSksCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gTkEsIAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0KSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID10ZXh0ZGYgLCBhZXMoeCA9IFYxLCB5ID0gVjIsIGxhYmVsID0gbmFtZXMpLAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLCAKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCkgKwogIGdndGl0bGUoInQtU05FIikgKwogIHRoZW1lX2xpZ2h0KGJhc2Vfc2l6ZT0xMCkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSxwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSJpdGFsaWMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9IiMzQzU0ODhGRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0PTAuMDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVoZWlnaHQ9MS4yLG1hcmdpbiA9IG1hcmdpbih0ID0gNSwgYiA9IC0xNSkpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICAjIHRpdGwpCnAyCmBgYApDb2RlIHRvIGNyZWF0ZSBhbiBpdGVyYWN0aXZlIHBsb3QuIFRoaXMgY2FuIGJlIG1vZGlmaWVkIHRvIGJlIHVzZWQgd2l0aCBhbGwgdGhlIHBsb3RzLgoKYGBge3IgZWNobz1UUlVFfQoKcCA9IGdncGxvdChkX3RzbmVfMSwgYWVzKHg9VjEsIHk9VjIsIHRleHQ9IHBhc3RlKCJnZW5lOiAiLG5hbWVzKSkpICsgIAogIGdlb21fcG9pbnQoc2l6ZT0yLCBhZXMoY29sb3VyPWFzLmNoYXJhY3RlcihoY2x1c3QpKSwgYWxwaGE9MC44KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMyKSAgKwogIHhsYWIoIiIpICsgeWxhYigiIikgKwogIGdndGl0bGUoInQtU05FIikgKwogIHRoZW1lX2xpZ2h0KGJhc2Vfc2l6ZT0xMCkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCkpCgpnZ3Bsb3RseShwKQpgYGAKCk11bHRpZGltZW5zaW9uYWwgc2NhbGluZyAoTURTKSBhbmQgcGxvdApgYGB7cn0KIyBydW4gdGhlIE1EUwpnZW5lcy5kaXN0LmV1YyA9ICBkaXN0KGcuc3BhY2UsIG1ldGhvZCA9ICAiZXVjbGlkZWFuIikKI2ZpdCA8LSBpc29NRFMoZ2VuZXMuZGlzdC5ldWMpICMgbm90IGxpbmVhcgpmaXQgPC0gaXNvTURTKGdlbmVzLmRpc3QuZXVjKQoKZml0LmdlbmVzID0gYXMuZGF0YS5mcmFtZShmaXQkcG9pbnRzKQoKZml0LmdlbmVzID0gZml0LmdlbmVzW29yZGVyLmRlbmRyb2dyYW0oZGVuZCksXQoKZml0LmdlbmVzJGhjbHVzdCA9IGN1dAoKCmZpdC5nZW5lcyRuYW1lcyA9IHJvd25hbWVzKGZpdC5nZW5lcykKCm15Y29sb3VyczMgPC0gYygiY2x1c3RlciBMNS82IG1hcmtlcnMiID0gIiMzQzU0ODhGRiIsImNsdXN0ZXIgTDIvMyBtYXJrZXJzIj0iI0YzOUI3RkZGIiwiY2x1c3RlciBQcm9nIG1hcmtlcnMiPSIjNERCQkQ1RkYiLCJjbHVzdGVyIEwxIG1hcmtlcnMiPSIjRTY0QjM1RkYiLCJjbHVzdGVyIEw0IG1hcmtlcnMiID0gIiM5MUQxQzJGRiIsICJub3QgaWRlbnRpZmllZCBjbHVzdGVyIj0iI0IwOUM4NUZGIikKCiNmaXQuZ2VuZXMkaGNsdXN0ID0gZmFjdG9yKGN1dHJlZShoYy5ub3JtLCA3KSkKdXNlZCA9IHZlY3RvcigpCmZvciAoayBpbiBjKDE6bGVuZ3RoKGxheWVycykpKSB7CiAgI3ByaW50KGspCiAgdHQgPWFzLm51bWVyaWMoY3V0W2xheWVyc1tba11dXVsxXSkKICBmaXQuZ2VuZXNbZml0LmdlbmVzJGhjbHVzdCA9PSB0dCwiY2x1c3RlciJdID0gcGFzdGUoImNsdXN0ZXIiLG5hbWVzKGxheWVyc1trXSksIm1hcmtlcnMiLCBzZXAgPSAiICIgKQogIHVzZWQgPSBjKHVzZWQsY3V0W2xheWVyc1tba11dXVsxXSkKfQoKZml0LmdlbmVzW2ZpdC5nZW5lcyRoY2x1c3QgJWluJSAodW5pcXVlKGZpdC5nZW5lcyRoY2x1c3QpWyF1bmlxdWUoZml0LmdlbmVzJGhjbHVzdCkgJWluJSB1c2VkXSksXSRjbHVzdGVyID0gIm5vdCBpZGVudGlmaWVkIGNsdXN0ZXIiCgp0ZXh0ZGYgPC0gZml0LmdlbmVzW3Jvd25hbWVzKGZpdC5nZW5lcykgJWluJSBjKHVubGlzdChsYXllcnMpLHVubGlzdChjb250cm9scykpLF0KCiAgIGYxID0gZ2dwbG90KHN1YnNldChmaXQuZ2VuZXMsIWhjbHVzdCAlaW4lIHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKSApLCBhZXMoeD1WMSwgeT1WMikpICsgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsIGNvbG9yID0gIiNCMDlDODVGRiIsIHNpemU9MSkKCmYyID0gZjEgKyBnZW9tX3BvaW50KGRhdGEgPSBzdWJzZXQoZml0LmdlbmVzLCBoY2x1c3QgJWluJSB1bmlxdWUoY3V0W3VubGlzdChsYXllcnMpXSkgKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4PVYxLCB5PVYyLCBjb2xvdXI9Y2x1c3RlciksIHNpemU9MSxhbHBoYSA9IDAuNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgiU3RhdHVzIiwgdmFsdWVzID0gbXljb2xvdXJzMykgICsKICBzY2FsZV9maWxsX21hbnVhbCgiU3RhdHVzIiwgdmFsdWVzID0gbXljb2xvdXJzMykgICsgCiAgeGxhYigiIikgKyB5bGFiKCIiKSsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gVjEsIHkgPSBWMiwgbGFiZWwgPSByb3duYW1lcyh0ZXh0ZGYpLGZpbGw9Y2x1c3RlciksCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gTkEsIAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0iYm90aCIsCiAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gVjEsIHkgPSBWMiwgbGFiZWwgPSByb3duYW1lcyh0ZXh0ZGYpKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMSwgCiAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZ3RpdGxlKCJNRFMiKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplPTEwKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9Iml0YWxpYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0iIzNDNTQ4OEZGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3Q9MC4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWhlaWdodD0xLjIsbWFyZ2luID0gbWFyZ2luKHQgPSA1LCBiID0gLTE1KSksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjM0M1NDg4RkYiLGZhY2UgPSJpdGFsaWMiICksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICAjIHRpdGwpCgoKZjIgIysgZ2VvbV9lbmNpcmNsZShkYXRhID0gZml0LmdlbmVzLCBhZXMoZ3JvdXA9YDVfY2x1c3RlcnNgKSkgCmBgYAoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgo=